home *** CD-ROM | disk | FTP | other *** search
- /*****************************************************************************
- **
- ** Copyright 1998 by Ernest R. Schreurs.
- ** All rights reserved.
- ** Use of this source code is allowed under the following conditions:
- ** If you change anything, use a different program name.
- ** If you only port this code, you can use this program name.
- ** Apart from this, the source code is public domain.
- ** This program is totally free.
- ** Refer to the documentation for more information.
- **
- *****************************************************************************/
- #define MODULE "DCM2ATR.C"
- /*****************************************************************************
- ** NAME: DCM2ATR.C
- **
- ** Author : Ernest R. Schreurs
- ** Date : February 2, 1998
- ** Release : 01.01
- **
- ** Description : This program will convert a Diskcomm file to a SIO2PC
- ** disk image file, also known as ATR file.
- **
- *****************************************************************************/
-
- /*****************************************************************************
- == INCLUDE FILES
- *****************************************************************************/
- #include <stdio.h> /* For printf() and gets() */
- #include <ctype.h> /* For isalnum() and toupper() */
- #include <stdlib.h> /* For the exit function */
- #include <string.h> /* String and memory stuff */
-
- /*****************************************************************************
- == DEFINED SYMBOLS
- *****************************************************************************/
-
- #ifndef FALSE
- #define FALSE 0
- #endif
- #ifndef TRUE
- #define TRUE 1
- #endif
-
- #ifndef NULL
- #define NULL 0
- #endif
- #define PATH_LEN 128 /* Maximum path length */
-
- #define BUF_LEN 80 /* fgets buffer length */
- #define SUCCESS 1 /* Success is non-zero */
- #define FAILURE 0 /* Failure is zero */
-
- /*
- ** These are the compression types used to indicate the type of record.
- */
- #define DCM_CHANGE_BEGIN 0x41 /* Change only start of sector */
- #define DCM_DOS_SECTOR 0x42 /* 128 byte compressed sector */
- #define DCM_COMPRESSED 0x43 /* Uncompressed/compressed pairs*/
- #define DCM_CHANGE_END 0x44 /* Change only end of sector */
- #define DCM_FLUSH_BUFFER 0x45 /* Flush the buffer */
- #define DCM_SAME_AS_BEFORE 0x46 /* Same as previous non-zero */
- #define DCM_UNCOMPRESSED 0x47 /* Uncompressed sector */
-
- /*
- ** These are the density types.
- */
- #define DENSITY_SD 1 /* Single density, 90K */
- #define DENSITY_DD 2 /* Double density, 180K */
- #define DENSITY_ED 3 /* Enhanced density, 130K */
-
- /*****************************************************************************
- == MACRO DEFINITIONS
- *****************************************************************************/
- /*
- ** Macro for casting stuff to requirements of stupid
- ** standard library functions.
- */
-
- #define FGETS( buf, buf_len, file_ptr ) \
- (void *)fgets( (char *)buf, (int)buf_len, (FILE *)file_ptr )
-
- #define STRLEN( str ) \
- strlen( (const char *)(str) )
-
- /*
- ** Macro for getting input from the terminal,
- ** allowing the user to exit with either control Z or
- ** inputting the string ^Z to indicate intention of
- ** terminating the program.
- */
- #define GET_BUF() \
- { \
- if ( FGETS( buf, BUF_LEN, stdin ) == NULL ) \
- { \
- printf( "Terminated by ^Z\n" ); \
- panic(0); \
- } \
- if ( memcmp( buf, "^Z", 2 ) == 0 || memcmp( buf, "^z", 2 ) == 0 ) \
- { \
- printf( "Terminated by ^Z\n" ); \
- panic(0); \
- } \
- }
-
- #define PRINT( lst ) \
- { \
- if( diagnostics ) \
- { \
- printf lst; \
- } \
- }
-
- /*****************************************************************************
- == TYPE and STRUCTURE DEFINITIONS
- *****************************************************************************/
- typedef unsigned char bool; /* Boolean value */
- typedef unsigned char ubyte; /* Exactly eight bits, unsigned */
- typedef short int16; /* At least 16 bits, signed */
- typedef unsigned short uint16; /* At least 16 bits, unsigned */
- typedef long int32; /* At least 32 bits, signed */
- typedef unsigned long uint32; /* At least 32 bits, unsigned */
-
- /*
- ** SIO2PC image file header.
- */
- typedef struct
- {
- ubyte atr_hdr_lo; /* Header, sum of NICKATARI, low */
- ubyte atr_hdr_hi; /* and high bytes of the word */
- ubyte atr_siz_lo; /* Size of atr excluding header, */
- ubyte atr_siz_hi; /* expressed in paragraphs, low/high*/
- ubyte atr_sec_size_lo; /* Sector size, low byte */
- ubyte atr_sec_size_hi; /* Sector size, high byte */
- ubyte atr_hi_size_lo; /* High order portion of 32 bit size*/
- ubyte atr_hi_size_hi; /* of atr, low/high */
- ubyte atr_d_info; /* Copy protect/write protect flags */
- ubyte atr_sec_lo; /* Sector number of typical copy */
- ubyte atr_sec_hi; /* protected sector, low/high */
- ubyte atr_tunused[5]; /* Unused spare bytes */
- } atr_blk;
-
- /*****************************************************************************
- == IMPORTED VARIABLES
- *****************************************************************************/
- /*****************************************************************************
- == LOCAL ( HIDDEN ) VARIABLES
- *****************************************************************************/
- static FILE * atr_file; /* SIO2PC disk image file */
- static FILE * dcm_file; /* Diskcomm input file */
- static ubyte atr_path[PATH_LEN]; /* Output atr file spec */
- static ubyte dcm_path[PATH_LEN]; /* Input dcm file spec */
-
- static ubyte sec_buf[256]; /* The sector buffer */
- static ubyte sec_zer[256]; /* A sector buffer with zeroes */
-
- static uint32 cnt_41; /* Number of 0x41 blocks */
- static uint32 cnt_42; /* Number of 0x42 blocks */
- static uint32 cnt_43; /* Number of 0x43 blocks */
- static uint32 cnt_44; /* Number of 0x44 blocks */
- static uint32 cnt_45; /* Number of 0x45 blocks */
- static uint32 cnt_46; /* Number of 0x46 blocks */
- static uint32 cnt_47; /* Number of 0x47 blocks */
- static uint32 cnt_F9; /* Number of 0xF9 headers */
- static uint32 cnt_FA; /* Number of 0xFA headers */
-
- static int dcm_byte; /* Byte from the Diskcomm file */
- static ubyte density; /* Density type */
- static bool diagnostics; /* Print diagnostic data */
- static ubyte file_type; /* File type from header */
- static uint16 increment; /* Byte of path to increment */
- static bool large; /* Large file/small files */
- static bool last; /* Last pass */
- static uint16 max_sector; /* Highest sector number */
- static ubyte pass; /* Pass count */
- static ubyte pass_cnt; /* Pass counter */
- static ubyte pass_expected; /* Pass count we should be at */
- static uint32 sec_size; /* Sector size */
- static uint16 sector; /* Sector number */
- static uint16 sector_atr; /* Sector number written to atr file*/
- static uint16 sectors; /* Number of sectors on disk */
- static bool seq_flag; /* Sequential sector flag */
- static bool statistics; /* Print statistics information */
- static ubyte type; /* Type of compression */
-
- /*****************************************************************************
- == EXPORTED VARIABLES
- *****************************************************************************/
- /*****************************************************************************
- == IMPORTED FUNCTIONS
- *****************************************************************************/
- /*****************************************************************************
- == LOCAL ( HIDDEN ) FUNCTIONS
- *****************************************************************************/
- static void cleanup( void );
- static uint32 dcm2atr( void );
- static ubyte get_byte( void );
- static void panic( int error_level );
- static uint32 process_header( void );
- static void usage( char * cmd );
-
- /*****************************************************************************
- == EXPORTED FUNCTIONS
- *****************************************************************************/
- int main(); /* Normal entry point to it all */
-
- /*****************************************************************************
- == LOCAL ( HIDDEN ) FUNCTIONS
- *****************************************************************************/
-
- /*****************************************************************************
- ** NAME: cleanup()
- **
- ** PURPOSE:
- ** Cleanup any mess that was created.
- **
- ** DESCRIPTION:
- ** This function will attempt to close all open files and
- ** free allocated memory.
- **
- ** INPUT:
- ** - The file pointers and paths are used.
- **
- ** OUTPUT:
- ** The function returns nothing.
- **
- */
-
- static void cleanup( void )
- {
- if( dcm_file )
- {
- fclose( dcm_file );
- }
- if( atr_file )
- {
- fclose( atr_file );
- }
- return;
- }
-
- /*****************************************************************************
- ** NAME: dcm2atr()
- **
- ** PURPOSE:
- ** Read data from the .dcm file and convert it to sectors in the ATR file.
- **
- ** DESCRIPTION:
- ** This function will read the data and process it.
- **
- ** INPUT:
- ** Nothing.
- ** Data is taken from the dcm file.
- **
- ** OUTPUT:
- ** Writes the .atr file.
- ** Prints results.
- ** Returns SUCCESS if data converted successfully.
- ** Returns FAILURE if some error occurred.
- **
- */
-
- static uint32 dcm2atr( void )
- {
- uint16 bytes_done; /* Number of bytes filled */
- uint16 end_offset; /* Offset of end of string */
- ubyte fill_char; /* Fill character */
- uint16 level; /* Interpreted level of signal */
- uint16 offset; /* Offset into sector */
-
- /*
- ** The sequential flag tells us whether or not the next sector data is
- ** related to the next sector on the disk. Sectors that are all zeroes are
- ** not stored in the .dcm file, so this is indicated by a flag. The next
- ** sector number is then stored prior to that sector data. Get the
- ** sector number if the next sector is not the next sector in sequence.
- */
- do /* Until we find a flush buffer code */
- {
- if( seq_flag )
- {
- sector++; /* Next sequential sector */
- PRINT( ("Sequential sector: %u\n", sector ) );
- }
- else
- {
- sector = get_byte();
- sector += ( ((uint16)get_byte()) << 8 );
- PRINT( ("Jump to sector: %u\n", sector ) );
- }
-
- type = get_byte();
- seq_flag = ( type & 0x080 ) ? TRUE : FALSE;
- type &= 0x7F;
-
- PRINT( ("Type: %.2x sector: %u\n", type, sector ) );
-
- switch( type )
- {
- case DCM_CHANGE_BEGIN: /* 0x41 */
- cnt_41++;
- offset = get_byte();
- do /* Reverse copy to beginning */
- {
- sec_buf[offset] = get_byte();
- } while( offset-- );
- PRINT( ("Beginning of sector reached\n") );
- break;
- case DCM_DOS_SECTOR: /* 0x42 */
- cnt_42++;
- for( offset = 123; offset < 128; offset++ )
- {
- sec_buf[offset] = get_byte();
- }
- memset( sec_buf, sec_buf[123], 123 );
- break;
- case DCM_COMPRESSED: /* 0x43 */
- cnt_43++;
- for( offset = 0, bytes_done = 0; bytes_done < sec_size; )
- {
- end_offset = get_byte();
- while( offset != end_offset )
- {
- sec_buf[offset] = get_byte();
- offset = (++offset) & 0x0FF; /* Roll over 255 to 0 */
- bytes_done++;
- if( bytes_done == sec_size )
- break;
- } /* end while uncompressed string */
- PRINT( ("Uncompressed end\n") );
- if( bytes_done < sec_size )
- {
- end_offset = get_byte();
- fill_char = get_byte();
- do /* while end of compressed string not reached */
- {
- sec_buf[offset] = fill_char;
- offset = (++offset) & 0x0FF;
- bytes_done++;
- if( bytes_done == sec_size )
- break;
- } while( offset != end_offset );
- PRINT( ("Compressed end\n") );
- } /* End if space left in sector */
- } /* end for uncompressed/compressed pairs */
- break;
- case DCM_CHANGE_END: /* 0x44 */
- cnt_44++;
- offset = get_byte();
- do /* Copy bytes up to the end */
- {
- sec_buf[offset++] = get_byte();
- } while( offset < sec_size );
- PRINT( ("End of sector reached\n") );
- break;
- case DCM_FLUSH_BUFFER: /* 0x45 */
- cnt_45++;
- break;
- case DCM_SAME_AS_BEFORE: /* 0x46 */
- cnt_46++;
- break;
- case DCM_UNCOMPRESSED: /* 0x47 */
- cnt_47++;
- for( offset = 0; offset < sec_size; offset++ )
- {
- sec_buf[offset] = get_byte();
- }
- break;
- default:
- fprintf(stderr, "\n%s is not a valid Diskcomm archive,\n", dcm_path);
- fprintf(stderr, "or archive damaged, bad record type encountered.\n");
- if( !large )
- printf("Did you forget the /B switch in the COPY command?\n");
- panic( 255 );
- break;
- }
- if( type != DCM_FLUSH_BUFFER )
- {
-
- /*
- ** Write the sector data to the atr file. If we skipped sectors, we must
- ** fill these sectors with zeroes, and write them to the file first.
- ** Remember that the first three sectors are always 128 bytes.
- */
- for( sector_atr++; sector_atr < sector; sector_atr++ )
- {
- fwrite( sec_zer, 1, (sector_atr < 4) ? 128 : sec_size, atr_file );
- }
- fwrite( sec_buf, 1, (sector_atr < 4) ? 128 : sec_size, atr_file );
- }
- } while( type != DCM_FLUSH_BUFFER );
- }
-
- /*****************************************************************************
- ** NAME: get_byte()
- **
- ** PURPOSE:
- ** Get one byte from the .dcm file.
- **
- ** DESCRIPTION:
- ** This function will read one byte from the .dcm file, and return
- ** it as an unsigned byte.
- **
- ** INPUT:
- ** - The diskcomm file.
- **
- ** OUTPUT:
- ** The function returns an unsigned byte.
- **
- */
-
- static ubyte get_byte( void )
- {
-
- /*
- ** Get the next byte from the Diskcomm file.
- ** If we get an End Of File condition, this is an error, since we never
- ** call this function unless we are sure we need more bytes.
- */
- dcm_byte = fgetc( dcm_file );
-
- if( dcm_byte == EOF )
- {
- fprintf(stderr, "\n%s is not a valid Diskcomm archive,\n", dcm_path);
- fprintf(stderr, "premature end of file encountered.\n");
- if( !large )
- {
- printf("Did you merge all parts of this Diskcomm archive with the COPY command?\n");
- printf("Did you forget the /B switch in the COPY command?\n");
- printf("Did you copy the files in the proper order?\n");
- printf("Did you read the documentation?\n");
- }
- panic( 255 );
- }
-
- PRINT( ("get_byte returns %.2x\n", dcm_byte ) );
-
- return( ((ubyte)(dcm_byte & 0x0FF)) );
- }
-
- /*****************************************************************************
- ** NAME: panic()
- **
- ** PURPOSE:
- ** Abort all processing and terminate program.
- **
- ** DESCRIPTION:
- ** This function will attempt to close all open files and
- ** free allocated memory. It will then terminate the program.
- **
- ** INPUT:
- ** - The error level code to be handed to the Operating System.
- **
- ** OUTPUT:
- ** The function returns nothing. In fact, it does not return at all.
- **
- */
-
- static void panic( error_level )
- int error_level; /* Error level value to pass */
- {
- cleanup();
- exit( error_level );
- }
-
- /*****************************************************************************
- ** NAME: process_header()
- **
- ** PURPOSE:
- ** Process the data from the header of the .dcm file and store
- ** relevant information.
- **
- ** DESCRIPTION:
- ** This function will read the relevant data about the .dcm file
- ** and store it.
- **
- ** INPUT:
- ** Nothing.
- ** Data is read from the Diskcomm file.
- **
- ** OUTPUT:
- ** Prints results.
- ** Stores data related to the format and contents of the Diskcomm file.
- ** Returns SUCCESS if header was processed successfully.
- ** Returns FAILURE if some error occurred.
- **
- */
-
- static uint32 process_header( void )
- {
-
- /*
- ** Diskcomm files always start with either $FA or $F9.
- ** Files that start with $F9 are multiple file archives.
- ** Files that start with $FA are single file archives.
- ** The second byte holds the following pieces of information:
- ** The high order bit indicates whether or not this is the last pass.
- ** The next two bits specifies the disk format of the original disk.
- ** 00 is single denisty, 01 is double density, 10 is enhanced density.
- ** The last 5 bits indicate the pass count value.
- ** After this, we always find a two-byte sector number,
- ** stored in the 6502 low byte/high byte format.
- ** See below for more details.
- */
-
- /*
- ** Get the byte that specifies the file type.
- ** We might have to skip some bytes that were added by file transfers.
- ** If this is the first header, we are reading the first byte, and we
- ** cannot be expected to process junk, so then we must get either F9 or FA.
- */
- if( cnt_45 == 0 ) /* First header? */
- {
- file_type = get_byte();
- if( ( file_type != 0x0F9 ) && ( file_type != 0x0FA ) )
- {
- fprintf(stderr, "\n%s is not a valid Diskcomm archive,\n", dcm_path);
- fprintf(stderr, "it does not begin with F9 or FA.\n");
- return( FAILURE );
- }
- memset( sec_buf, 0x00, 256 ); /* Initialize sector buffer */
- } /* end if first header */
- else
- {
-
- /*
- ** The last thing we read from the file was the flush buffer code.
- ** If this is an archive that consists of only one file, we must now
- ** find the header for the first pass. If it is a multi file archive,
- ** there are two possibilities. Either we will now reach the end of the
- ** file, and we must close it and open the next file, or the user somehow
- ** merged the files, and we can continue reading this file. Either way,
- ** file transfer may have added bytes to the end of the archive file.
- ** Read bytes until we hit the header byte, or until we hit the end of
- ** file marker. At end of file, try to open the next file.
- */
- do /* Read bytes until we find a header byte */
- {
- dcm_byte = fgetc( dcm_file );
- file_type = ((ubyte)(dcm_byte & 0x0FF));
- PRINT( ("Looking for header byte found %.2x\n", file_type ) );
- if( dcm_byte == EOF )
- {
- fclose( dcm_file );
- (dcm_path[increment])++;
- dcm_file = fopen( (char *)dcm_path, "rb" );
- PRINT( ("Attempting to open %s.\n", dcm_path ) );
- if( dcm_file == NULL )
- {
- fprintf(stderr, "\nCannot open next Diskcomm archive file %s.\n",
- dcm_path );
- return( FAILURE );
- }
- dcm_byte = fgetc( dcm_file );
- if( dcm_byte == EOF )
- {
- fprintf(stderr, "\nNext file %s\n", dcm_path);
- fprintf(stderr, "is not a valid .dcm file, it does not begin with F9 or FA.\n");
- return( FAILURE );
- }
- file_type = ((ubyte)(dcm_byte & 0x0FF));
- PRINT( ("Looking for header byte found %.2x\n", file_type ) );
- if( ( file_type != 0x0F9 ) && ( file_type != 0x0FA ) )
- {
- fprintf(stderr, "\nNext file %s\n", dcm_path);
- fprintf(stderr, "is not a valid .dcm file, it does not begin with F9 or FA.\n");
- return( FAILURE );
- }
- }
- } while( ( file_type != 0x0F9 ) && ( file_type != 0x0FA ) );
- } /* End else if first header */
-
- if( file_type == 0x0F9 )
- {
- large = FALSE;
- cnt_F9++;
- memset( sec_buf, 0x00, 256 ); /* Initialize sector buffer */
- }
- else
- {
- large = TRUE;
- cnt_FA++;
- }
-
- /*
- ** Get the byte that specifies the pass count and the disk format.
- ** If the high order bit is set, this is the last pass.
- */
- pass = get_byte();
- last = ( pass & 0x080 ) ? TRUE : FALSE;
- density = (( pass & 0x60 ) >> 5 ) + 1;
- pass &= 0x1F;
-
- /*
- ** The pass count should match the expected pass count, otherwise
- ** this archive is corrupt. In this case it was probably assembled out
- ** of multiple smaller archive files. Concatenating them in the proper
- ** order is required for this program.
- */
- if( pass != pass_expected )
- {
- fprintf(stderr, "\nThe header indicated an out of sequence pass number.");
- fprintf(stderr, "\n%s is not a valid Diskcomm archive.\n", dcm_path);
- if( !large )
- {
- printf("Did you merge all parts of this Diskcomm archive with the COPY command?\n");
- printf("Did you forget the /B switch in the COPY command?\n");
- printf("Did you copy the files in the proper order?\n");
- printf("Did you read the documentation?\n");
- }
- return( FAILURE );
- }
-
- /*
- ** Well, we processed the header.
- ** This looks like what we wanted, so we will call this success.
- */
-
- return( SUCCESS );
- }
-
- /*****************************************************************************
- ** NAME: usage()
- **
- ** PURPOSE:
- ** Display the command line format for the program.
- **
- ** DESCRIPTION:
- ** This function will explain the usage of the program to the user.
- ** The program name is taken from the first command line argument.
- **
- ** INPUT:
- ** - The address of the command line, containing the program name.
- **
- ** OUTPUT:
- ** The usage is displayed on the terminal.
- ** The function returns nothing.
- **
- */
-
- static void usage( cmd )
- char * cmd; /* Program name */
- {
- char * whoami; /* For searching program name in command line */
- char * name; /* Pointer to actual program name in command */
- int len; /* Length of program name */
- int found_dot; /* Nonzero if we found a dot in the name */
-
- /*
- ** Get program name and print usage message.
- ** The complete pathname including extension is part of the first
- ** argument as passed by the operating system.
- */
- for( whoami = cmd, len = 0, found_dot = 0; *whoami; whoami++ )
- {
- if( *whoami == '.' )
- {
- found_dot = 1;
- continue;
- }
-
- /*
- ** If this was part of the path
- */
- if( ( *whoami == '\\' ) || ( *whoami == '/' ) )
- {
- name = whoami + 1; /* record position */
- len = 0; /* then restart counting length */
- found_dot = 0;
- continue;
- }
- if( *whoami == ' ' ) /* end of name found */
- break;
- if( found_dot ) /* skip .exe or .com stuff */
- continue;
- len++; /* Increment program name length */
- }
-
- /*
- ** Let me explain...
- */
- fprintf(stderr, "\nUsage: %.*s [DCM file] [ATR file] [/d] [/h=nnnn] [/s]\n", len, name);
- fprintf(stderr, "to convert a .dcm file to an .atr disk image.\n\n");
- fprintf(stderr, "DCM file a file created by the Diskcomm program.\n");
- fprintf(stderr, "ATR file a file in the SIO2PC disk image format.\n\n");
- fprintf(stderr, "/d to print diagnostic information.\n");
- fprintf(stderr, "/h=nnnn highest sector number to expect,\n");
- fprintf(stderr, " where nnnn is a number from 1 to 9999.\n");
- fprintf(stderr, "/s to print statistics information.\n\n");
- fprintf(stderr, "Refer to the documentation for more information.\n");
-
- return;
- }
-
- /*****************************************************************************
- == EXPORTED FUNCTIONS
- *****************************************************************************/
-
- /*****************************************************************************
- ** NAME: MAIN()
- **
- ** PURPOSE:
- ** An entry point for testing or running this utility.
- **
- ** DESCRIPTION:
- ** Prompt for the file to open and then go process it.
- **
- ** INPUT:
- ** argc and argv.
- **
- ** OUTPUT:
- ** Returns an int as it should.
- **
- */
- int main( argc, argv )
- int argc; /* Command line argument count */
- char * argv[]; /* Command line argument ptrs */
- {
- ubyte answer; /* Response to yes/no question */
- uint32 arg_ndx; /* Argument number index */
- uint32 arg_no; /* Argument number */
- atr_blk atr; /* The header for the atr image */
- uint32 atr_siz; /* Size of ATR file excl. hdr */
- uint32 wrk_ndx; /* Work index */
- bool end_of_str; /* Null terminator seen? */
- uint32 hdr = 'N'+'I'+'C'+'K' +
- 'A'+'T'+'A'+'R'+'I';
- ubyte buf[BUF_LEN]; /* Buffer string */
- uint32 stat; /* Status from function */
- ubyte proceed; /* Proceed with conversion */
-
- /*
- ** Set default values for unused command switches.
- */
- atr_path[0] = 0x00;
- dcm_path[0] = 0x00;
- diagnostics = FALSE;
- statistics = FALSE;
- max_sector = 0;
- pass_cnt = 0;
- pass_expected = 0;
-
- /*
- ** Process command line arguments.
- ** We do not treat the options switch as an argument. It may be placed
- ** anywhere on the command line. So we have to count the arguments ourselves
- ** so that we know what argument we are processing.
- ** If this program is ported to the Atari ST, the program name is not
- ** on the command line, so the program should then be adapted.
- */
- arg_no = 0;
-
- for( arg_ndx = 1; arg_ndx < argc; arg_ndx++ )
- {
-
- /*
- ** If we encounter the options switch, process the options.
- ** The options must start with a slash.
- */
- if( ( argv[arg_ndx][0] == '/' ) || ( argv[arg_ndx][0] == '-' ) )
- {
-
- for( wrk_ndx = 0; argv[arg_ndx][wrk_ndx]; wrk_ndx++ )
- {
-
- /*
- ** If the user is confused, seeking help, she/he should read the * manual.
- ** We can give them a hint though.
- */
- if( argv[arg_ndx][wrk_ndx] == '?' )
- {
- usage( argv[0] );
- panic( 0 ); /* Not really an error */
- }
-
- /*
- ** The /d option selects the diagnostics output.
- */
- if( toupper( argv[arg_ndx][wrk_ndx] ) == 'D' )
- {
- diagnostics = TRUE;
- continue;
- }
-
- /*
- ** The /h option selects the highest sector number we should expect.
- ** Diskcomm calls this the Maximum sector number your drive is capable
- ** of reading. This happens to be option H in the menu.
- ** The format of this switch is /h=nnnn where nnnn is a numeric value
- ** that within Diskcomm can range from 1 to 9999. We accept any number
- ** the user enters though. This option is only needed for non-standard
- ** disk sizes, where we want the proper number of sectors with zeroes
- ** at the end of the disk image. This cannot be used to truncate a disk.
- */
- if( toupper( argv[arg_ndx][wrk_ndx] ) == 'H' )
- {
- while( argv[arg_ndx][++wrk_ndx] )
- {
- if( ( argv[arg_ndx][wrk_ndx] >= '0' ) &&
- ( argv[arg_ndx][wrk_ndx] <= '9' ) )
- {
- max_sector *= 10;
- max_sector += argv[arg_ndx][wrk_ndx] - '0';
- }
- }
- break;
- }
-
- /*
- ** The /s option selects the statistics output.
- */
- if( toupper( argv[arg_ndx][wrk_ndx] ) == 'S' )
- {
- statistics = TRUE;
- continue;
- }
-
- /*
- ** Ignore other options.
- */
- continue;
- } /* end for all characters after options switch */
-
- /*
- ** No further processing for the options switches.
- */
- continue;
- } /* end if options switch */
- arg_no++;
-
- /*
- ** First argument is the file spec for the Diskcomm file.
- */
- if( arg_no == 1 )
- {
- for ( wrk_ndx = 0, end_of_str = FALSE;
- wrk_ndx < PATH_LEN; wrk_ndx++ )
- {
- if ( argv[arg_ndx][wrk_ndx] == '\0' ) /* End of argument string? */
- end_of_str = TRUE;
- if ( end_of_str )
- dcm_path[wrk_ndx] = '\0';
- else
- dcm_path[wrk_ndx] = toupper( argv[arg_ndx][wrk_ndx] );
- }
- }
-
- /*
- ** Optionally the name of the SIO2PC image file can be entered as the second
- ** command line argument. If it is not specified, the input path is copied,
- ** and the extension is replaced by .atr.
- */
- if( arg_no == 2 )
- {
- for ( wrk_ndx = 0, end_of_str = FALSE;
- wrk_ndx < PATH_LEN; wrk_ndx++ )
- {
- if ( argv[arg_ndx][wrk_ndx] == '\0' ) /* End of argument string? */
- end_of_str = TRUE;
- if ( end_of_str )
- atr_path[wrk_ndx] = '\0';
- else
- atr_path[wrk_ndx] = toupper( argv[arg_ndx][wrk_ndx] );
- }
-
- }
- } /* end for all command line arguments */
-
- /*
- ** If there is no filename on the command line, ask for it.
- */
- if( ( arg_no == 0 ) || ( dcm_path[0] == 0x00 ) )
- {
-
- /*
- ** Open hailing frequencies.
- ** No command line arguments, so ask what it is we have to do.
- */
- printf( "\n\nDiskcomm DCM archive to SIO2PC ATR disk image converter.\n" );
- printf( "Version February 2, 1998\n" );
- printf( "\nCopyright 1998 by Ernest R. Schreurs\n" );
- printf( "\nAll rights reserved\n" );
-
-
- while( TRUE ) /* until terminated by control Z*/
- {
- printf( "\nEnter ^Z or hit Control Z to terminate\n" );
- if( dcm_file )
- {
- fclose( dcm_file );
- dcm_file = NULL;
- }
- if( atr_file )
- {
- fclose( atr_file );
- atr_file = NULL;
- }
-
- do /* until .dcm file entered */
- {
- printf("\nEnter .dcm file to be converted : ");
- GET_BUF();
-
- for ( wrk_ndx = 0, end_of_str = FALSE;
- wrk_ndx < PATH_LEN; wrk_ndx++ )
- {
- if ( wrk_ndx < BUF_LEN )
- {
- if ( buf[wrk_ndx] == '\n' ) /* End of inputted string? */
- end_of_str = TRUE;
- if ( buf[wrk_ndx] == '\0' ) /* Overkill, End marked by \n */
- end_of_str = TRUE;
- if ( end_of_str )
- dcm_path[wrk_ndx] = '\0';
- else
- dcm_path[wrk_ndx] = toupper( buf[wrk_ndx] );
- }
- }
- } while ( dcm_path[0] == ' ' );
-
- do /* until answer is Y or N */
- {
- printf("\nConvert file %s\n", dcm_path);
- printf("\nIs this correct Y)es or N)o : ");
- GET_BUF();
- proceed = toupper( buf[0] );
-
- /*
- ** If blank, default is correct
- */
- if ( proceed == '\n' )
- proceed = 'Y';
-
- } while ( proceed != 'Y' && proceed != 'N' );
-
- if ( proceed == 'N' )
- continue;
-
- dcm_file = fopen( (char *)dcm_path, "rb" );
- if( dcm_file == NULL )
- {
- fprintf(stderr, "Cannot open Diskcomm file\n");
- continue;
- }
-
- do /* until .atr file entered */
- {
- printf("\nEnter .atr file to be created : ");
- GET_BUF();
-
- for ( wrk_ndx = 0, end_of_str = FALSE;
- wrk_ndx < PATH_LEN; wrk_ndx++ )
- {
- if ( wrk_ndx < BUF_LEN )
- {
- if ( buf[wrk_ndx] == '\n' ) /* End of inputted string? */
- end_of_str = TRUE;
- if ( buf[wrk_ndx] == '\0' ) /* Overkill, End marked by \n */
- end_of_str = TRUE;
- if ( end_of_str )
- atr_path[wrk_ndx] = '\0';
- else
- atr_path[wrk_ndx] = toupper( buf[wrk_ndx] );
- }
- }
- } while ( atr_path[0] == ' ' );
-
- do /* until answer is Y or N */
- {
- printf("\nConvert file %s to %s\n", dcm_path, atr_path);
- printf("\nIs this correct Y)es or N)o : ");
- GET_BUF();
- proceed = toupper( buf[0] );
-
- /*
- ** If blank, default is correct
- */
- if ( proceed == '\n' )
- proceed = 'Y';
-
- } while ( proceed != 'Y' && proceed != 'N' );
-
- if ( proceed == 'N' )
- continue;
-
- /*
- ** Check to see that we can open the file.
- */
- atr_file = fopen( (char *)atr_path, "rb" );
- if( atr_file != NULL )
- {
- fprintf(stderr, "Specified SIO2PC image file %s already exists.\n", atr_path);
- fclose( atr_file );
- continue;
- }
- atr_file = fopen( (char *)atr_path, "wb+" );
- if( atr_file == NULL )
- {
- fprintf(stderr, "Cannot open SIO2PC image file %s\n", atr_path);
- continue;
- }
-
- /*
- ** Ask for diagnostics option.
- */
- do /* until answer is Y or N */
- {
- printf("\nPrint diagnostic data Y)es or N)o : ");
- GET_BUF();
- answer = toupper( buf[0] );
-
- /*
- ** If blank, default is no diagnostics
- */
- if ( answer == '\n' )
- answer = 'N';
-
- } while ( answer != 'Y' && answer != 'N' );
-
- diagnostics = ( answer == 'Y' ) ? TRUE : FALSE;
-
- /*
- ** Ask for statistics option.
- */
- do /* until answer is Y or N */
- {
- printf("\nPrint statistics Y)es or N)o : ");
- GET_BUF();
- answer = toupper( buf[0] );
-
- /*
- ** If blank, default is print statistics
- */
- if ( answer == '\n' )
- answer = 'Y';
-
- } while ( answer != 'Y' && answer != 'N' );
-
- /*
- ** Ask for highest sector number.
- */
- printf("\nEnter highest sector number : ");
- GET_BUF();
- max_sector = 0;
-
- for( wrk_ndx = 0; wrk_ndx < BUF_LEN; wrk_ndx++ )
- {
- if ( buf[wrk_ndx] == '\n' ) /* End of inputted string? */
- break;
- if ( buf[wrk_ndx] == '\0' ) /* Overkill, End marked by \n */
- break;
- if( ( buf[wrk_ndx] >= '0' ) &&
- ( buf[wrk_ndx] <= '9' ) )
- {
- max_sector *= 10;
- max_sector += buf[wrk_ndx] - '0';
- }
- }
-
- printf( "\nConverting data from Diskcomm file.\n" );
- break;
- } /* end while need a valid filename */
- } /* end if no command line arguments */
- else
- {
-
- /*
- ** Replace .dcm extension by .atr extension, or add .atr if there is
- ** no extension at all. If it all fits that is.
- ** If the user really wants, it is possible to make this code fail.
- ** That is their loss.
- */
- if( atr_path[0] == 0x00 )
- {
- memcpy( atr_path, dcm_path, PATH_LEN );
- wrk_ndx = STRLEN( atr_path );
- if( wrk_ndx > 4 )
- if( atr_path[wrk_ndx - 4] == '.' )
- wrk_ndx -= 4;
- if( wrk_ndx + 5 <= PATH_LEN )
- memcpy( &(atr_path[wrk_ndx]), ".ATR", 5 );
- }
-
- /*
- ** Try to open the file that was specified on the command line.
- */
- dcm_file = fopen( (char *)dcm_path, "rb" );
- if( dcm_file == NULL )
- {
- fprintf(stderr, "Cannot open Diskcomm file %s\n", dcm_path);
- panic( 255 );
- }
-
- atr_file = fopen( (char *)atr_path, "rb" );
- if( atr_file != NULL )
- {
- fprintf(stderr, "Specified SIO2PC image file %s already exists.\n", atr_path);
- fclose( atr_file );
- panic( 255 );
- }
- atr_file = fopen( (char *)atr_path, "wb+" );
- if( atr_file == NULL )
- {
- fprintf(stderr, "Cannot open SIO2PC image file %s\n", atr_path);
- panic( 255 );
- }
- } /* end else if no command line arguments */
-
- /*
- ** For multi file archives, determine the character to be incremented
- ** in the path specification.
- ** Try to find a "1" or an "A" starting at the end of the path
- ** specification, working our way back.
- ** If we hit the directory marker, use the last character before the file
- ** extension. If there is no extension, us the last character in the
- ** filename.
- */
- increment = PATH_LEN;
-
- for( wrk_ndx = STRLEN( dcm_path); wrk_ndx--; )
- {
- if( ( dcm_path[wrk_ndx] == '1' ) ||
- ( dcm_path[wrk_ndx] == 'A' ) )
- {
- increment = wrk_ndx;
- break;
- }
- if( ( dcm_path[wrk_ndx] == '.' ) &&
- ( wrk_ndx > 0 ) )
- {
- increment = wrk_ndx - 1;
- continue;
- }
- if( ( dcm_path[wrk_ndx] == '\\' ) ||
- ( dcm_path[wrk_ndx] == '/' ) )
- {
- if( increment == PATH_LEN )
- increment = STRLEN( dcm_path );
- break;
- }
- }
-
- /*
- ** Initialize some stuff.
- */
- memset( sec_zer, 0x00, 256 );
- sector_atr = 0;
- cnt_41 = 0;
- cnt_42 = 0;
- cnt_43 = 0;
- cnt_44 = 0;
- cnt_45 = 0;
- cnt_46 = 0;
- cnt_47 = 0;
- cnt_F9 = 0;
- cnt_FA = 0;
-
- do /* until last pass processed */
- {
-
- /*
- ** Process the header of the .dcm file.
- */
- pass_cnt++;
- if( pass_cnt & 0x20 )
- pass_expected = pass_cnt - 1; /* For some odd reason */
- else
- pass_expected = pass_cnt; /* Pass we should find next */
- pass_expected &= 0x1F;
-
- stat = process_header();
- if( stat == FAILURE )
- {
- panic( 255 );
- }
-
- PRINT( ("File : %s\n", dcm_path ) );
- PRINT( ("Density: %u\n", density ) );
-
- /*
- ** Based on the density, compute the number of sectors and the
- ** sector size. Note that the user can modify the highest sector number
- ** as one of the options in Diskcomm. So these sector counts are only
- ** defaults. Diskcomm might even be able to compress an entire hard disk.
- */
- switch( density )
- {
- case DENSITY_SD:
- sectors = 720;
- sec_size = 128;
- break;
- case DENSITY_ED:
- sectors = 1040;
- sec_size = 128;
- break;
- case DENSITY_DD:
- sectors = 720;
- sec_size = 256;
- break;
- default:
- sectors = 720;
- sec_size = 128;
- break;
- }
-
- /*
- ** If non-standard size specified, use it instead.
- */
- if( max_sector )
- sectors = max_sector;
-
- /*
- ** The size of the ATR file is specified in paragraphs, a paragraph on the
- ** PC is 16 bytes. The size of the header, which is always 16 bytes,
- ** is not included in this size value. The size of the ATR file can thus
- ** be computed by multiplying the total number of sectors by the sector size,
- ** and dividing this value by 16. Unless it is a double density disk.
- ** The first three sectors of any Atari double density disk are always
- ** 128 bytes in size, so that the machine can always boot these three
- ** sectors. In ATR files, these three sectors are stored as 128 bytes
- ** of data. So this must be subtracted to compute the proper size.
- */
- atr_siz = sectors * sec_size;
- if( density == DENSITY_DD )
- {
- if( sectors > 3 )
- atr_siz -= 3 * 128;
- else
- atr_siz = sectors * 128;
- }
- atr_siz = atr_siz >> 4; /* Convert to paragraphs, divide by 16 */
-
-
- /*
- ** Write the header to the SIO2PC image file.
- */
- if( sector_atr == 0 )
- {
- memset( &atr, 0x00, sizeof( atr_blk ) );
- atr.atr_hdr_lo = hdr; /* Header, sum of NICKATARI */
- atr.atr_hdr_hi = hdr >> 8;
- atr.atr_siz_lo = atr_siz; /* Size of atr excluding header */
- atr.atr_siz_hi = atr_siz >> 8;
- atr.atr_sec_size_lo = sec_size; /* Sector size */
- atr.atr_sec_size_hi = sec_size >> 8;
- atr.atr_hi_size_lo = atr_siz >> 16; /* High order part of size */
- atr.atr_hi_size_hi = atr_siz >> 24;
- atr.atr_d_info = 0; /* Copy protect/write protect flags */
- atr.atr_sec_lo = 0; /* Sector number of typical copy */
- atr.atr_sec_hi = 0; /* protected sector, low/high */
-
- fwrite( &atr, 1, sizeof( atr_blk ), atr_file );
- }
-
- /*
- ** Process the data portion of the .dcm file.
- */
- stat = dcm2atr();
-
- } while( !last );
-
- /*
- ** Make sure the last sectors of the disk are zeroes.
- */
- while( ++sector_atr <= sectors )
- {
- fwrite( sec_zer, 1, (sector_atr < 4) ? 128 : sec_size, atr_file );
- }
-
- /*
- ** If this is a non-standard diskette size, the actual size must be
- ** adjusted in the header. We have no way of knowing the physical
- ** ending sector, if the user did not specify this. In that case, the
- ** last non-zero sector determines the disk size. If the user did
- ** specify this, this will have been recorded in the header already,
- ** and we only have to adjust it if the user made a mistake.
- */
- sector_atr--;
- if( sector_atr > sectors )
- {
- atr_siz = sector_atr * sec_size; /* Compute real size */
- if( density == DENSITY_DD )
- {
- if( sector_atr > 3 )
- atr_siz -= 3 * 128;
- else
- atr_siz = sector_atr * 128;
- }
- atr_siz = atr_siz >> 4; /* Convert to paragraphs, divide by 16 */
-
- /*
- ** Update header and write it out again.
- */
- atr.atr_siz_lo = atr_siz; /* Size of atr excluding header */
- atr.atr_siz_hi = atr_siz >> 8;
- atr.atr_hi_size_lo = atr_siz >> 16; /* High order portion of size */
- atr.atr_hi_size_hi = atr_siz >> 24;
-
- fseek( atr_file, 0L, SEEK_SET ); /* Go back to beginning of file */
- fwrite( &atr, 1, sizeof( atr_blk ), atr_file );
- }
-
- cleanup();
-
- if( statistics )
- {
- printf("\nStatistics for Diskcomm archive file %s:\n\n", dcm_path );
- switch( density )
- {
- case DENSITY_SD:
- printf("Single density");
- break;
- case DENSITY_DD:
- printf("Double density");
- break;
- case DENSITY_ED:
- printf("Enhanced density");
- break;
- default:
- printf("Unknown density");
- break;
- }
- printf(" %lu Kbyte.\n", atr_siz >> 6 );
- printf("FA large header : %lu\n", cnt_FA );
- printf("F9 small header : %lu\n", cnt_F9 );
- printf("41 modify begin : %lu\n", cnt_41 );
- printf("42 123 byte/5 byte: %lu\n", cnt_42 );
- printf("43 compressed : %lu\n", cnt_43 );
- printf("44 modify end : %lu\n", cnt_44 );
- printf("45 flush buffer : %lu\n", cnt_45 );
- printf("46 identical : %lu\n", cnt_46 );
- printf("47 uncompressed : %lu\n", cnt_47 );
- printf(" Total number : %lu\n", cnt_41 + cnt_42 + cnt_43 +
- cnt_44 + cnt_46 + cnt_47 );
- printf(" Disk sectors : %u\n", sector_atr );
-
- printf("\nDone processing.\n");
- }
-
- return 0;
- }
-
- /*****************************************************************************
- ** MODIFICATION HISTORY
- **
- ** DATE BY Description
- ** ---------- --- ---------------------------------------------------------
- ** 1998/01/04 ERS Start coding, after many hours of research
- ** 1998/01/18 ERS Release 01.00
- ** 1998/02/02 ERS Release 01.01 Initialize previous sector buffer when
- ** processing next pass for multi-file archives.
- **
- *****************************************************************************/
-